/*
 * @(#) $Header$
 *
 * Copyright (C) 2007  Forklabs Daniel Léonard
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package ca.forklabs.media.jai.operator;

import java.awt.RenderingHints;
import java.awt.image.RenderedImage;
import java.util.Arrays;
import java.util.Collection;
import javax.media.jai.EnumeratedParameter;
import javax.media.jai.JAI;
import javax.media.jai.OperationDescriptor;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.ParameterListDescriptor;
import javax.media.jai.operator.DFTDataNature;
import javax.media.jai.operator.DFTScalingType;
import javax.media.jai.registry.CollectionRegistryMode;
import ca.forklabs.media.jai.CollectionDescriptor;

/**
 * Class {@code IDFT3DDescriptor} is an {@link OperationDescriptor} describing
 * the <em>idft</em> operation for the collection mode. This operation performs
 * an inverse 3D Fourier transform on the collection as if it were a cubic data.
 * <p>
 * The <em>idft</em> operation takes two parameter: - the scaling type and -
 * the data nature.
 * <p>
 * Finally, all the images in the collection must be {@link RenderedImage}.
 *
 * <table border=1>
 * <caption>Resource List</caption>
 * <tr><th>Name</th>        <th>Value</th></tr>
 * <tr><td>GlobalName</td>  <td>idft</td></tr>
 * <tr><td>LocalName</td>   <td>idft</td></tr>
 * <tr><td>Vendor</td>      <td>ca.forklabs.media.jai.opimage</td></tr>
 * <tr><td>Description</td> <td>3D inverse Fourier transform</td></tr>
 * <tr><td>DocURL</td>      <td>n/a</td></tr>
 * <tr><td>Version</td>     <td>$Version$</td></tr>
 * <tr><td>Arg0Desct</td>   <td>The data scaling type</td></tr>
 * <tr><td>Arg1Desct</td>   <td>The data nature</td></tr>
 * </table>
 *
 * <table border=1>
 * <caption>Parameter List</caption>
 * <tr><th>Name</th>          <th>Class Type</th>               <th>Default Value</th></tr>
 * <tr><td>scalingType</td>   <td>{@link DFTScalingType}</td>   <td>{@link #SCALING_DIMENSIONS}</td>
 * <tr><td>dataNature</td>    <td>{@link DFTDataNature}</td>    <td>{@link #COMPLEX_TO_REAL}</td>
 * </table>
 *
 * @author   <a href="mailto:forklabs at gmail.com?subject=ca.forklabs.media.jai.operator.IDFT3DDescriptor">Daniel Léonard</a>
 * @version $Revision$
 */
public class IDFT3DDescriptor extends CollectionDescriptor {

//---------------------------
// Class variables
//---------------------------

   /** <em>serialVersionUID</em>. */
   private static final long serialVersionUID = -7533738120094575186L;

   /**
    * No scaling of the spectral data is made.
    */
   public static final DFTScalingType SCALING_NONE = DFT3DDescriptor.SCALING_NONE;

   /**
    * The spectral data is divided by the square root of the product of the
    * <em>cubic image</em> dimension.
    */
   public static final DFTScalingType SCALING_UNITARY = DFT3DDescriptor.SCALING_UNITARY;

   /**
    * The spectral data is divided by the product of the <em>cubic image</em>
    * dimension.
    */
   public static final DFTScalingType SCALING_DIMENSIONS = DFT3DDescriptor.SCALING_DIMENSIONS;


   /**
    * Indicates that the source data is in the real domain and that the sink
    * data is expected to be in the complex domain.
    */
   public static final DFTDataNature REAL_TO_COMPLEX = DFT3DDescriptor.REAL_TO_COMPLEX;

   /**
    * Indicates that the source data is in the complex domain and that the sink
    * data is expected to be in the complex domain.
    */
   public static final DFTDataNature COMPLEX_TO_COMPLEX = DFT3DDescriptor.COMPLEX_TO_COMPLEX;

   /**
    * Indicates that the source data is in the complex domain and that the sink
    * data is expected to be in the real domain.
    */
   public static final DFTDataNature COMPLEX_TO_REAL = DFT3DDescriptor.COMPLEX_TO_REAL;


   /** The name of this operator. */
   public static final String NAME = "IDFT"; //$NON-NLS-1$

   /** The name of the scaling parameter. */
   public static final String SCALING_PARAMETER_NAME = DFT3DDescriptor.SCALING_PARAMETER_NAME;
   /** The name of the nature parameter. */
   public static final String NATURE_PARAMETER_NAME = DFT3DDescriptor.NATURE_PARAMETER_NAME;

   /** The index in the parameter block of the scaling parameter. */
   public static final int SCALING_PARAMETER_INDEX = DFT3DDescriptor.SCALING_PARAMETER_INDEX;
   /** The index in the parameter block of the nature parameter. */
   public static final int NATURE_PARAMETER_INDEX = DFT3DDescriptor.NATURE_PARAMETER_INDEX;

   /** The default value for the scaling type. */
   public static final DFTScalingType SCALING_DEFAULT_VALUE = IDFT3DDescriptor.SCALING_DIMENSIONS;
   /** The default value for the data nature. */
   public static final DFTDataNature NATURE_DEFAULT_VALUE = IDFT3DDescriptor.COMPLEX_TO_REAL;

   /**
    * The resource strings that provide the general documentation and specify
    * the parameter list for this operation.
    */
   private static final String[][] RESOURCES =
   {
      { "GlobalName",  IDFT3DDescriptor.NAME, }, //$NON-NLS-1$
      { "LocalName",   IDFT3DDescriptor.NAME, }, //$NON-NLS-1$
      { "Vendor",      "ca.forklabs.media.jai.opimage", }, //$NON-NLS-1$  //$NON-NLS-2$
      { "Description", IDFT3DDescriptor.getDescription(), }, //$NON-NLS-1$
      { "DocURL",      "n/a", }, //$NON-NLS-1$  //$NON-NLS-2$
      { "Version",     "$Version$", }, //$NON-NLS-1$  //$NON-NLS-2$
      { "arg0Desc",    IDFT3DDescriptor.getArg0Description(), }, //$NON-NLS-1$
      { "arg1Desc",    IDFT3DDescriptor.getArg1Description(), }, //$NON-NLS-1$
   };

   /** The supported modes. */
   private static final String[] SUPPORTED_MODES =
   {
      CollectionRegistryMode.MODE_NAME,
   };

   /** The name of the source, use default. */
   private static final String[] SOURCE_NAMES = null;

   /** The type of source for each mode. */
   private static final Class<?>[][] SOURCE_CLASSES = new Class<?>[][]
   {
      { Collection.class, },
   };

   /** The parameter list descriptor for all modes. */
   private static final ParameterListDescriptor PARAMETER_LIST_DESCRIPTOR = new CollectionDescriptor.EmptyParameterListDescriptor() {

      @Override
      public String[] getEnumeratedParameterNames() {
         String[] names = new String[] {
            IDFT3DDescriptor.SCALING_PARAMETER_NAME,
            IDFT3DDescriptor.NATURE_PARAMETER_NAME,
            };
         return names;
         }

      @Override
      public EnumeratedParameter[] getEnumeratedParameterValues(String name) {
         EnumeratedParameter[] values;
         if (DFT3DDescriptor.SCALING_PARAMETER_NAME.equalsIgnoreCase(name)) {
            values = new EnumeratedParameter[] {
               IDFT3DDescriptor.SCALING_NONE,
               IDFT3DDescriptor.SCALING_UNITARY,
               IDFT3DDescriptor.SCALING_DIMENSIONS,
               };
            }
         else if (DFT3DDescriptor.NATURE_PARAMETER_NAME.equalsIgnoreCase(name)) {
            values = new EnumeratedParameter[] {
               IDFT3DDescriptor.REAL_TO_COMPLEX,
               IDFT3DDescriptor.COMPLEX_TO_COMPLEX,
               IDFT3DDescriptor.COMPLEX_TO_REAL,
               };
            }
         else {
         // this call throws an exception
            values = super.getEnumeratedParameterValues(name);
            }
         return values;
         }

      @Override
      public int getNumParameters() {
         int num_parameters = 2;
         return num_parameters;
         }

      @Override
      public Class<?>[] getParamClasses() {
         Class<?>[] clazzes = new Class<?>[] {
            DFTScalingType.class,
            DFTDataNature.class,
            };
         return clazzes;
         }

      @Override
      public Object getParamDefaultValue(String name) {
         int index;
         if (IDFT3DDescriptor.SCALING_PARAMETER_NAME.equals(name)) {
            index = IDFT3DDescriptor.SCALING_PARAMETER_INDEX;
            }
         else if (IDFT3DDescriptor.NATURE_PARAMETER_NAME.equals(name)) {
            index = IDFT3DDescriptor.NATURE_PARAMETER_INDEX;
            }
         else {
         // this call throws an exception
            return super.getParamDefaultValue(name);
            }

         Object[] values = this.getParamDefaults();
         Object value = values[index];
         return value;
         }

      @Override
      public Object[] getParamDefaults() {
         Object[] defaults = new Object[] {
            IDFT3DDescriptor.SCALING_DEFAULT_VALUE,
            IDFT3DDescriptor.NATURE_DEFAULT_VALUE,
            };
         return defaults;
         }

      @Override
      public String[] getParamNames() {
         String[] names = new String[] {
            IDFT3DDescriptor.SCALING_PARAMETER_NAME,
            IDFT3DDescriptor.NATURE_PARAMETER_NAME,
            };
         return names;
         }

      @Override
      public boolean isParameterValueValid(String name, Object value) {
         EnumeratedParameter[] values = this.getEnumeratedParameterValues(name);
         Collection<EnumeratedParameter> set = Arrays.asList(values);
         boolean is_valid = set.contains(value);
         return is_valid;
         }

      };

   /** Description of the parameters. */
   private static final ParameterListDescriptor[] PARAMETER_LIST_DESCRIPTORS = new ParameterListDescriptor[]
   {
      IDFT3DDescriptor.PARAMETER_LIST_DESCRIPTOR,
   };


//---------------------------
// Constructor
//---------------------------

   /**
    * Constructor.
    */
   public IDFT3DDescriptor() {
      super(RESOURCES, SUPPORTED_MODES, SOURCE_NAMES, SOURCE_CLASSES, PARAMETER_LIST_DESCRIPTORS);
      }


//---------------------------
// Class methods
//---------------------------

   /**
    * Creates and fills a new parameter block.
    * @param   mode   the rendering mode.
    * @param   source   the source image.
    * @param   scaling   the scaling strategy.
    * @param   nature   the nature of the data.
    * @return   a new parameter block.
    */
   protected static ParameterBlockJAI createParameterBlock(String mode, Object source, DFTScalingType scaling, DFTDataNature nature) {
      String name = IDFT3DDescriptor.NAME;
      ParameterBlockJAI pb = new ParameterBlockJAI(name, mode);
      if (null != source) {
         pb.addSource(source);
         }
      pb.setParameter(IDFT3DDescriptor.SCALING_PARAMETER_NAME, scaling);
      pb.setParameter(IDFT3DDescriptor.NATURE_PARAMETER_NAME, nature);
      return pb;
      }

   /**
    * Creates and fills a new parameter block for the rendered mode.
    * @param   sources   the source images.
    * @param   scaling   the scaling strategy.
    * @param   nature   the nature of the data.
    * @return   a new parameter block.
    */
   public static ParameterBlockJAI createParameterBlock(Collection<RenderedImage> sources, DFTScalingType scaling, DFTDataNature nature) {
      String mode = CollectionRegistryMode.MODE_NAME;
      ParameterBlockJAI pb_jai = IDFT3DDescriptor.createParameterBlock(mode, sources, scaling, nature);
      return pb_jai;
      }


   /**
    * Performs the operation on a collection of image.
    * @param   sources   the source images.
    * @param   scaling   the scaling strategy.
    * @param   nature   the nature of the data.
    * @param   hints    the rendering hints, may be {@code null}.
    * @return   the rendered result image.
    */
   @SuppressWarnings("unchecked")
   public static Collection<RenderedImage> createCollection(Collection<RenderedImage> sources, DFTScalingType scaling, DFTDataNature nature, RenderingHints hints)  {
      String name = IDFT3DDescriptor.NAME;
      ParameterBlockJAI parameter_block = IDFT3DDescriptor.createParameterBlock(sources, scaling, nature);
      Collection<RenderedImage> sinks = JAI.createCollection(name, parameter_block, hints);
      return sinks;
      }


//---------------------------
// External resources methods
//---------------------------

   /**
    * Gets the description of this operation.
    * @return   the description message.
    */
   protected static String getDescription() {
      String key = Resources.IDFT3D_DESCRIPTION;
      String message = Resources.getLocalizedString(key);
      return message;
      }

   /**
    * Gets the description for the first argument, the scaling type.
    * @return   the description message.
    */
   protected static String getArg0Description() {
      String message = DFT3DDescriptor.getArg0Description();
      return message;
      }

   /**
    * Gets the description for the second argument, the data nature.
    * @return   the description message.
    */
   protected static String getArg1Description() {
      String message = DFT3DDescriptor.getArg1Description();
      return message;
      }

   }
